import mqtt from 'mqtt'

const config = {
  protocol: 'ws',
  host: '36.111.45.214',
  port: 6004,
  endpoint: '/mqtt',
  clean: true,
  connectTimeout: 30 * 1000,
  reconnectPeriod: 4000,
  clientId: 'mindService_' + Math.random().toString(16).substring(2, 8),
  username: 'adminxx',
  password: 'hh112233',
}

const subList = [
  { topic: 'jdzb/pcmonitor/midService/feedBack/' + config.clientId, qos: 0 },
  { topic: 'jdzb/pcmonitor/midService/feedBack/All', qos: 0 },
  { topic: '$SYS/brokers/+/clients/#', qos: 0 },
  { topic: '$SYS/brokers/+/datetime', qos: 0 },
]

export class MqttHelper {
  constructor() {
    if (MqttHelper.instance) {
      return MqttHelper.instance
    }
    this.handleList = []
    try {
      const { protocol, host, port, endpoint, ...options } = config
      const connectUrl = `${protocol}://${host}:${port}${endpoint}`
      console.log('Connection options!', options)
      this.client = mqtt.connect(connectUrl, options)
      this.client.on('connect', () => {
        console.log('mqtt 服务连接成功!')
        for (let sub of subList) window.M.doSubscribe(sub)
      })
      this.client.on('reconnect', () => {
        console.log('正在尝试重新连接！')
      })
      this.client.on('error', (error) => {
        console.log('mqtt 发生异常：', error)
      })
      this.client.on('message', (topic, message) => {
        // $EVBUS.$emit('mqttMessage', { topic, message: message.toString() })
        // console.log('mqtt 消息接收：', topic, message.toString())
        this.handleList.forEach((handle) => {
          let msgObj = null
          try {
            msgObj = JSON.parse(message)
          } catch (ex) {
            msgObj = message
          }
          handle({ topic, message: msgObj })
        })
      })
    } catch (error) {
      console.log('mqtt 连接失败!', error)
    }
    MqttHelper.instance = this
  }

  addFeedBackHandle(handle) {
    this.handleList.push(handle)
  }

  doPublish({ topic, qos, payload }) {
    /*
      MQTT中的QoS（Quality of Service）具体作用是确保消息的稳定传输。它提供了三种不同层次的服务质量（QoS）：
      QoS 0，即At most once，至多一次。这意味着消息发送方（Sender）发送一条消息后，接收方（Receiver）最多只能收到一次。
      如果消息发送失败，Sender不会进行重试。
  
      QoS 1，即At least once，至少一次。这意味着消息发送方发送一条消息后，接收方至少能收到一次。
      如果消息发送失败，Sender会进行重试以确保消息被接收。
  
      QoS 2，即Exactly once，确保只有一次。这意味着消息发送方发送一条消息后，接收方只能收到一次。
      如果消息发送失败，Sender会进行重试，但同时会检查消息的唯一性以防止重复接收。
    */
    // console.log('call doPublish', topic, qos, payload)

    return new Promise((resolve, reject) => {
      try {
        payload['sender'] = config.clientId
        payload = JSON.stringify(payload)
        this.client.publish(topic, payload, { qos }, (error) => {
          if (error) {
            resolve({ code: -1, msg: '推送失败！', error })
          } else {
            resolve({ code: 0, msg: '推送成功！' })
          }
        })
      } catch (e) {
        console.log('推送失败：topic:', topic, 'qos:', qos)
        console.log('payload:', payload)
        console.log(e)
        resolve({ code: -1, msg: '推送失败！,详情请查看控制台' })
      }
    })
  }

  doSubscribe({ topic, qos }) {
    this.client.subscribe(topic, { qos }, (error, res) => {
      if (error) {
        // console.log(`${topic} 订阅失败`, error)
        return
      }
      // console.log(`${topic} 已订阅`)
    })
  }
}
